﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GcmpRenderingInterface.h"
#include "WeakPtr.h"

namespace gcmp
{

    class ElementId;
    class IGraphicsElementShape;
    struct ElementIdHash;
    class Coordinate3d;
    class Box2d;
    class IModelView;
    class ICanvas;

    const int MIN_LOAD_SPEED = 50;

    //加载速度信息
    struct BatchLoadSpeedInfo
    {
        int LoadSpeed = MIN_LOAD_SPEED;  ///< 默认加载速度
        int MaxLimitRefreshTime = 1000; ///< 单位ms，当前画布中构件刷完的极限时间。达到极限时间直接刷完。该值会根据数量动态变化
        float ScaleOfSpeedInHalfTime = 2; ///< 达到极限时间的一半时设置速度系数，默认加载速度*2
    };
    struct BatchLoadParams
    {
        int RefreshAllHighPriorityNumLimitByCameraChanged = 300; ///<  相机变化时高优先级（屏幕范围内）待刷新的构件数低于该值，一次性直接刷完。
        int MaxBatchLoadGrepsNum = 30000;  ///<  允许参加分批加载的最大数量；超过该数量必须直接绘制出来，不能被阈值等过滤。该值会根据数量动态变化
        int EnableBatchLoadGrepsMinNum = 5000; ///<  开启分批加载的最小数量；低于该值不开启该功能。
    };

    class GCMP_RENDERING_INTERFACE_EXPORT IBatchLoadFilter
    {
    public:
        /// \brief 是否需要过滤掉实例化打包的element
        /// 如果当前视图开启了实例化打包，一般需要过滤掉；尤其是三维、立面，受分批加载影响很大的视图。
        /// \param modelview 当前视图
        /// \return 返回是否需要过滤掉
        virtual bool IsNeedFilterInstanceCombineElement(const IModelView& modelview) const = 0;
    };

    ///该类注册后，每个视图需要再modelview中单独设置阈值来开启每个视图的分批加载功能。
    /// \brief分批加载GREP功能管理器
    class GCMP_RENDERING_INTERFACE_EXPORT IBatchLoadHandler
    {
    public:
        static OwnerPtr<IBatchLoadHandler> CreateDefaultBatchLoadHandler();

        virtual ~IBatchLoadHandler() {};

#pragma region 动态配置项

        /// \brief 当每次分批加载刷新后获取相关信息，每次刷新完会调用
        /// numInScreenNeedRefresh <= numInSceneNeedRefresh <= visibleGrepsNum，产品可以根据这些参数知道每次完还剩下多少没刷新。
        /// \param pCanvas 当前正在刷新的canvas指针
        /// \param visibleGrepsNum，当前场景中所有可见的greps数量。
        /// \param highPriorityNeedRefreshNum，高优先级需要刷的剩余数
        /// \param numInSceneNeedRefresh，当前场景中中剩余需要刷新的数量个数。
        virtual void AfterOnceBatchRenderRefresh(const ICanvas* pCanvas, int visibleGrepsNum, int highPriorityNeedRefreshNum, int numInSceneNeedRefresh) = 0;

        /// \brief 更新分批加载的速度
        /// 每次相机发生变化时调用，可动态调整刷新速度;.
        /// 默认是>5000构件每次刷500；大于500每次刷200；200以下每次刷50；
        /// \param pCanvas 当前正在刷新的canvas指针
        /// \param visibleGrepsNum，当前场景中所有可见的greps数量。
        /// \param highPriorityNeedRefreshNum，高优先级需要刷的剩余数
        /// \param numInSceneNeedRefresh，当前场景中中剩余需要刷新的数量个数。
        /// \return返回pCanvas的刷新速度值
        virtual BatchLoadSpeedInfo UpdateSpeed(const ICanvas* pCanvas, int visibleGrepsNum, int  highPriorityNeedRefreshNum, int  numInSceneNeedRefresh) = 0;

        /// \brief 获取高优先刷新的element
        /// 默认返回false，使用平台内部自定义的规则。目前是每次相机发生改变时触发调用。
        /// \param pCanvas 当前正在刷新的canvas指针
        /// \param visibleGrepsNum，当前场景中所有可见的greps数量。
        /// \param allNeedBatchRenderElement，所有需要刷新的element
        /// \return 返回高优先级待加载的，返回为空，平台默认使用当前屏幕范围内的作为高优先级待加载构件。
        virtual std::unordered_set<ElementId, ElementIdHash> GetHighPriorityNeedLoadElement(const ICanvas* pCanvas, const std::map<ElementId, WeakPtr<const IGraphicsElementShape>>& visibleGreps,
            const std::unordered_map<ElementId, int, ElementIdHash>& allNeedBatchRenderElement) = 0;

        /// \brief 更新最大限制数量
        /// 在场景重建时会调用，平台会根据可见的数量等比例提高限制上限。最小值平台默认不变
        /// \param pCanvas 当前正在刷新的canvas指针
        /// \param visibleGreps，可见grep的数量。
        virtual BatchLoadParams GetInfoOfPrepareBegin(const ICanvas* pCanvas, int visibleGreps) = 0;

        /// \brief pCanvas中的分批加载greps全部刷新完毕
        /// \param pCanvas 当前正在刷新的canvas指针
        virtual void EndBatchRender(const ICanvas* pCanvas) = 0;

        /// \brief 设置分批加载过滤器
        ///
        /// \param  filter 过滤器
        virtual void SetIBatchLoadFilter(OwnerPtr<IBatchLoadFilter> filter) = 0;

        /// \brief 获取分批加载过滤器
        ///
        /// \return 分批加载过滤器
        virtual const IBatchLoadFilter* GetIBatchLoadFilter() = 0;

#pragma endregion 动态配置项
    };
}
